package io.renren.common.aspect;

import io.renren.common.annotation.ReqLimit;
import io.renren.common.exception.RRException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * ReqLimitAspect切面处理类
 */
@Aspect
@Component
@Order(1)
public class ReqLimitAspect {

    public static final String REQUEST_LIMIT = "requestLimit";

    /**
     * 频率限制切入点(注解类的路径)
     */
    @Pointcut(value = "@annotation(io.renren.common.annotation.ReqLimit)")
    public void reqLimitPointCut() {
    }

    /**
     * 切面请求频率限制
     *
     * @param joinPoint joinPoint
     */
    @Before("reqLimitPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        HttpSession session = this.getCurrentUserSession();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        ReqLimit reqLimit = methodSignature.getMethod().getAnnotation(ReqLimit.class);

        if (session == null) {
            // 请求不合法
            throw new RRException("请求不合法");
        }

        if (session.getAttribute(REQUEST_LIMIT) == null) {
            // 在session中存放请求的相关信息
            session.setAttribute(REQUEST_LIMIT, new HashMap<String, Long>());
        }

        Map<String, Long> map = (Map<String, Long>) session.getAttribute(REQUEST_LIMIT);
        String methodName = signature.getDeclaringTypeName() + "." + signature.getName();

        Long lastReqTime = map.get(methodName);
        if (lastReqTime != null) {
            int interval = (int) (System.currentTimeMillis() - lastReqTime) / 1000;
            if (interval < reqLimit.rateSecond()) {
                map.put(methodName, System.currentTimeMillis());
                // 请求过于频繁抛出异常,项目中可以自己定一个全局异常来处理
                throw new RRException("请求过于频繁");
            }
        }
        // 这里设置当前时间，作为下一次请求是获取的 lastReqTime（上一次请求时间）
        map.put(methodName, System.currentTimeMillis());
    }

    /**
     * 获取当前session
     *
     * @return
     */
    private HttpSession getCurrentUserSession() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request.getSession();
    }
}


